/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Peer;

import FileStructure.ClientRequest;
import FileStructure.FileHandler;
import FileStructure.Response;
import FileStructure.Response.IPPort;
import Peer.peerRequest.*;
import Peer.sender.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.net.*;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import model.PeerEntity;

/**
 *
 * @author bangyo17
 */
public class PeerRequest implements Runnable{

    
    PeerEntity Peer;
    public String dir;
    public String torrentName;
    public String mysqlpass;
    //port TCP
    

    public PeerRequest(String IP, int port, boolean completed) {
        //super(System.out, 15);
        Peer = new PeerEntity(IP,port,completed);
        Peer.request = new ClientRequest("");
    }

    public PeerRequest(PeerEntity pe, String mpass){
        this.Peer = pe;
        Peer.request = new ClientRequest("");
        this.mysqlpass = mpass;
    }

    public void openConnection(){
        try {
            
            Peer.url = new URL("http://localhost:8080/TrackerWeb/ReverseServlet");
            Peer.connection = Peer.url.openConnection();
            Peer.connection.setDoOutput(true);
        } catch (IOException ex) {
            Logger.getLogger(PeerRequest.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void addPortTCP(int p, String service) {
        pTCP pr = new pTCP(p,service);
        Peer.portTCP.add(pr);
       // System.out.println(pr.port);
    }

    public void removePortTCP(int p) {
        Peer.portTCP.remove(p);
    }

    public boolean isSeeder(String filename) {
        if (filename.equalsIgnoreCase(Peer.request.file_name)) {
            if (Peer.request.left == 0) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }


    //setter buat protokol peer
//    public void setHandShake(String hashed_filename){
//        Peer.hs = new handShakeType(hashed_filename);
//    }
//
//    public void setBlockRequest(int idx, int begin, int length){
//        Peer.br = new blockRequest(idx,begin,length);
//    }
//
//    public void setBitField(ArrayList<Byte> bf){
//        Peer.bf = new bitField(bf);
//    }
//
//    public void setCancel(int idx, int begin, int length){
//        Peer.ca = new cancel(idx,begin,length);
//    }
//
//    public void setHave(int piece_idx){
//        Peer.hv = new have(piece_idx);
//    }
//
//    public void setKeepAliveType(){
//        Peer.ke = new keepAliveType();
//    }
//
//    public void setPiece(int idx, int begin, ArrayList<Byte> bf){
//        Peer.pi = new piece(idx,begin,bf);
//    }


    //method buat request
    //stop request dengan sengaja
    public void stopRequest() {
        {
            OutputStreamWriter out = null;
            try {
                Peer.request.event = "stopped";
                Peer.isDownloading = false;
                
                Peer.openConnection();
                System.out.println("STOPPING...");
                String request = Peer.request.file_name + ";;" + Peer.port + ";;" + Peer.request.uploaded + ";;" + 
                        Peer.request.downloaded + ";;" + Peer.request.left + ";;" + Peer.request.event;
                String stringToReverse = URLEncoder.encode(request, "UTF-8");
                out = new OutputStreamWriter(Peer.connection.getOutputStream());
                out.write("string=" + stringToReverse);
                out.close();
            } catch (IOException ex) {
                Logger.getLogger(PeerRequest.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                try {
                    out.close();
                } catch (IOException ex) {
                    Logger.getLogger(PeerRequest.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    public void completedRequest() {
        {
            OutputStreamWriter out = null;
            try {
                Peer.request.event = "completed";
                Peer.isDownloading = false;

                Peer.openConnection();
                System.out.println("STOPPING...");
                String request = Peer.request.file_name + ";;" + Peer.port + ";;" + Peer.request.uploaded + ";;" +
                        Peer.request.downloaded + ";;" + Peer.request.left + ";;" + Peer.request.event;
                String stringToReverse = URLEncoder.encode(request, "UTF-8");
                out = new OutputStreamWriter(Peer.connection.getOutputStream());
                out.write("string=" + stringToReverse);
                out.close();
            } catch (IOException ex) {
                Logger.getLogger(PeerRequest.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                try {
                    out.close();
                } catch (IOException ex) {
                    Logger.getLogger(PeerRequest.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    
    public void startRequest() throws UnknownHostException, InterruptedException {
        //request pertamax nih gan
        //kirim this ke socket pake TCP
        Peer.openConnection();
//        Peer.request.uploaded = uploaded;
//        Peer.request.downloaded = downloaded;
//        Peer.request.left = left;
//        Peer.request.file_name = filename;
        Peer.request.event = "started";
        try {
            String request = Peer.request.file_name+";;"+Peer.port+";;"+Peer.request.uploaded+";;"+
                            Peer.request.downloaded+";;"+Peer.request.left+";;"+Peer.request.event+";;"+this.mysqlpass;
            String stringToReverse = URLEncoder.encode(request, "UTF-8");
            
            OutputStreamWriter out = new OutputStreamWriter(Peer.connection.getOutputStream());
            //out.flush();
            out.write("string="+stringToReverse);
            out.close();
            
        } catch (IOException ex) {
            Logger.getLogger(PeerRequest.class.getName()).log(Level.SEVERE, null, ex);
        }
        this.getResponseFromTracker("response.txt");
    }

    public void updateRequest(int interval) {

       
        try {
            Peer.request.event="";
            while(!Peer.downloadComplete){
                Peer.openConnection();
                System.out.println("UPDATING...");
                String request = Peer.request.file_name+";;"+Peer.port+";;"+Peer.request.uploaded+";;"+
                            Peer.request.downloaded+";;"+Peer.request.left+";;"+Peer.request.event+";;"+this.mysqlpass;
                String stringToReverse = URLEncoder.encode(request, "UTF-8");

                OutputStreamWriter out = new OutputStreamWriter(Peer.connection.getOutputStream());
                out.write("string="+stringToReverse);
                out.close();
                if (this.Peer.isDownloading){
//                long currd = Peer.request.downloaded;
//                currd += 10; //ntar diganti SPEED
//                Peer.request.downloaded = currd;
                }
                System.out.println("downloaded = " + Peer.request.downloaded);
                //Peer.writeResponseFile("test", "response.txt");
                this.getResponseFromTracker("response.txt");
                Thread.sleep(interval*1000);
            }
            this.completedRequest();
            this.stopRequest();

        } catch (InterruptedException ex) {
            Logger.getLogger(PeerRequest.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(PeerRequest.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void getResponseFromTracker(String filename){
        BufferedReader in = null;
        ArrayList<PeerEntity> peerlist = new ArrayList<PeerEntity>();
        try {
            in = new BufferedReader(new InputStreamReader(Peer.connection.getInputStream()));
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                //System.out.println(inputLine);
                String[] peer = inputLine.split("##");
                //String[] peer_details = peer
                //peer[0] = interval
                //peer[1-N] = id,ip,port,complete
                Peer.resp.interval = Integer.parseInt(peer[0]);
                System.out.println("interval = " +Peer.resp.interval);
                Peer.resp.peers = new ArrayList<IPPort>();
                for(int i=1; i<peer.length; i++){
                    System.out.println(peer[i]);
                    String[] attribute = peer[i].split(";;");
                    boolean iss = false;
                    if (Integer.parseInt(attribute[2]) == 1) iss = true;
                    peerlist.add(new PeerEntity(
                                                attribute[0],
                                                Integer.parseInt(attribute[1]),
                                                iss)
                                );
                }
                int num_completed = 0;
                for(int i=0; i<peerlist.size(); i++){
                    if (peerlist.get(i).isSeeder) {
                        num_completed++;
                    }
                    Peer.resp.addPeer(peerlist.get(i).IP, peerlist.get(i).port);
                }
                Peer.resp.complete = num_completed;
                Peer.resp.incomplete = peerlist.size() - num_completed;
                this.writeResponseFile(dir.substring(0,dir.length()-1), filename);

            }
            //in.close();
        } catch (IOException ex) {
            Logger.getLogger(PeerRequest.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                in.close();
            } catch (IOException ex) {
                Logger.getLogger(PeerEntity.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
    
    
//    public void startHandShake(int port) throws UnknownHostException, InterruptedException {
//        //request pertamax nih gan
//        //kirim this ke socket pake TCP
//        InetAddress addr = InetAddress.getByName(null);
//        NewHandShake cr = new NewHandShake(addr, port, Peer.hs.pstrlen, Peer.hs.pstr, Peer.hs.reserved, Peer.hs.info_hash);
//
//
//        Thread.currentThread().sleep(500);
//    }
//
//    public void startHave(int port) throws UnknownHostException, InterruptedException{
//        InetAddress addr = InetAddress.getByName(null);
//        NewHave cr = new NewHave(addr, port, Peer.hv.len, Peer.hv.id, Peer.hv.piece_index);
//
//
//        Thread.currentThread().sleep(500);
//    }
//
//
//    public void startBlockRequest(int port) throws UnknownHostException, InterruptedException{
//        InetAddress addr = InetAddress.getByName(null);
//        NewBlockRequest cr = new NewBlockRequest(addr, port, Peer.br.len, Peer.br.id, Peer.br.index, Peer.br.begin, Peer.br.length);
//
//
//        Thread.currentThread().sleep(500);
//    }
//
//    public void startCancel(int port) throws UnknownHostException, InterruptedException{
//         InetAddress addr = InetAddress.getByName(null);
//        NewCancel cr = new NewCancel(addr, port, Peer.br.len, Peer.br.id, Peer.br.index, Peer.br.begin, Peer.br.length);
//
//
//        Thread.currentThread().sleep(500);
//    }
//
//    public void startKeepAlive() throws UnknownHostException, InterruptedException{
//
//    }
//
//
//
//    public void updateNoDownload(int interval, String filename, boolean stopped) throws FileNotFoundException, UnknownHostException, InterruptedException {
//        Peer.request.event = "";
//        //boolean stop = false;
//
//        //cari ukuran file
//        InetAddress addr = InetAddress.getByName(null);
//        //panggil fungsi updateFromDB di sini
//
//        if (stopped) {
//            Peer.request.event = "stopped";
//        }
//        NewClientRequest cr = new NewClientRequest(addr, Peer.request.file_name,
//                Peer.port,
//                Peer.request.uploaded,
//                Peer.request.downloaded,
//                Peer.request.left,
//                Peer.request.event);
//
//        Thread.currentThread().sleep(interval * 1000);
//        writeResponseFile("test/", "response.txt");
//
//    }

    public void writeResponseFile(String Target, String filename) {
        //write ke FILE
        //inputnya dari kelas statik NewClientRequestt
        //tambahin port mana aja yg tersedia di setiap peer (bukan cuma por HTTP, tapi TCP juga)

        try {
            File file = new File(Target + "/" + filename);
            FileOutputStream fos = new FileOutputStream(file);


            new PrintStream(fos).println("failure_reason " + Peer.resp.failure_reason);
            new PrintStream(fos).println("warning_message " + Peer.resp.warning_message);
            new PrintStream(fos).println("interval " + Peer.resp.interval);
            new PrintStream(fos).println("complete " + Peer.resp.complete);
            new PrintStream(fos).println("incomplete " + Peer.resp.incomplete);
            new PrintStream(fos).print("peers");

            for (int i = 0; i < Peer.resp.peers.size(); i++) {
                new PrintStream(fos).print(" " + Peer.resp.peers.get(i).IP + ":" + Peer.resp.peers.get(i).Port);
            }
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }



    }
    
    
    //TESTER
    public static void main(String[] args) throws UnknownHostException, InterruptedException, FileNotFoundException, IOException, IllegalAccessException, InstantiationException {
       PeerRequest peer1 = new PeerRequest("127.0.0.1",1234,true);
       PeerRequest peer2 = new PeerRequest("127.0.0.1",1235,false);

       //peer1.openConnection();
       peer1.Peer.readFileTorrent("test/", "laguku.mp3.torrent");
       peer1.startRequest();
       //peer1.updateRequest(peer1.Peer.resp.interval);
       //peer1.updateRequest(5);
//       peer2.openConnection();
//       peer2.startRequest("laguku.mp3",1235,4443,5544,22);
//       peer2.getResponseFromTracker("laguku_response_2.txt");
    }

    public void run() {
        try {
            System.out.println("Request to Tracker...");
            this.Peer.readFileTorrent(dir, this.torrentName);
            if (this.Peer.request.file_name != null){
                this.startRequest();
                this.updateRequest(Peer.resp.interval);
            }
        } catch (UnknownHostException ex) {
            Logger.getLogger(PeerRequest.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InterruptedException ex) {
            Logger.getLogger(PeerRequest.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
